import java.util.HashMap;

public class HashIntIntMapResourceTest {
	private static int DATASET_SIZE = 16 * 1024 * 1024;

	private static void runJavaSetTest(boolean warmUp) {
		long m;
		long sum = 0;
		long checkSum = 0;

		// Prepare data.
		int[] keys = new int[DATASET_SIZE];
		int[] data = new int[DATASET_SIZE];
		for (int i = 0; i < DATASET_SIZE; i++) {
			keys[i] = i;
			data[i] = (int) (Math.random() * DATASET_SIZE);
			checkSum += data[i];
		}
		mixKeys(keys, DATASET_SIZE);

		// Main run.
		System.gc();
		m = Runtime.getRuntime().freeMemory();
		long t = System.nanoTime();
		HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
		for (int i = 0; i < DATASET_SIZE; i++) {
			hashMap.put(keys[i], data[i]);
		}
		long deltaT = System.nanoTime() - t;

		// Some actions.
		System.gc();
		m = m - Runtime.getRuntime().freeMemory();

		// Let's do another run, getting the elements (keyset is shuffled
		// again).
		mixKeys(keys, DATASET_SIZE);
		t = System.nanoTime();
		for (int i = 0; i < DATASET_SIZE; i++) {
			sum += hashMap.get(keys[i]);
		}
		deltaT += System.nanoTime() - t;

		// Print the results.
		if (!warmUp) {
			System.out.println("HashMap<Integer, Integer>, total size = " + m
					+ ", per pair: " + m / DATASET_SIZE);
			System.out.printf("Put & get time, total, sec: %.3f\n",
					(double) deltaT / 1000 / 1000 / 1000);
			System.out.println("Put & get time, per pair, nanos: "
					+ (deltaT / DATASET_SIZE));
		}

		if (checkSum == sum) {
			System.out.println("CORRECT RUN.");
		} else {
			System.out.println("ERROR. INCORRECT RUN.");
		}

		// Just for disabling optimizer from doing it's work.
		for (int i = 0; i < 16; i++) {
			int randomKey = (int) (Math.random() * DATASET_SIZE);
			if (hashMap.containsKey(randomKey)) {
				sum += hashMap.get(randomKey) + data[randomKey]
						+ keys[randomKey];
			}
		}

		System.out.println("*** " + sum + " ***");
	}

	private static void mixKeys(int[] keys, int datasetSize) {
		for (int k = 0; k < datasetSize; k++) {
			int i = (int) (Math.random() * datasetSize);
			int j = (int) (Math.random() * datasetSize);
			int temp = keys[i];
			keys[i] = keys[j];
			keys[j] = temp;
		}
	}

	private static void runTest(boolean warmUp) {
		long m;
		long sum = 0;
		long checkSum = 0;

		// Prepare data.
		int[] keys = new int[DATASET_SIZE];
		int[] data = new int[DATASET_SIZE];
		for (int i = 0; i < DATASET_SIZE; i++) {
			keys[i] = i;
			data[i] = (int) (Math.random() * DATASET_SIZE);
			checkSum += data[i];
		}
		mixKeys(keys, DATASET_SIZE);

		// Main run.
		System.gc();
		m = Runtime.getRuntime().freeMemory();
		long t = System.nanoTime();
		HashIntIntMap hashMap = new HashIntIntMap();
		for (int i = 0; i < DATASET_SIZE; i++) {
			hashMap.put(keys[i], data[i]);
		}
		long deltaT = System.nanoTime() - t;

		// Some actions.
		System.gc();
		m = m - Runtime.getRuntime().freeMemory();

		// Let's do another run, getting the elements (keyset is shuffled
		// again).
		mixKeys(keys, DATASET_SIZE);
		t = System.nanoTime();
		for (int i = 0; i < DATASET_SIZE; i++) {
			Integer obj = hashMap.get(keys[i]);
			if (obj != null) {
				sum += obj;
			}
		}
		deltaT += System.nanoTime() - t;

		// Print the results.
		if (!warmUp) {
			System.out.println("HashIntIntMap, total size = " + m
					+ ", per pair: " + m / DATASET_SIZE);
			System.out.printf("Put & get time, total, sec: %.3f\n",
					(double) deltaT / 1000 / 1000 / 1000);
			System.out.println("Put & get time, per pair, nanos: "
					+ (deltaT / DATASET_SIZE));
		}

		if (!warmUp) {
			if (checkSum == sum) {
				System.out.println("CORRECT RUN.");
			} else {
				System.out.println("ERROR. INCORRECT RUN.");
			}
		}

		// Just for disabling optimizer from doing it's work.
		for (int i = 0; i < 16; i++) {
			int randomKey = (int) (Math.random() * DATASET_SIZE);
			if (hashMap.containsKey(randomKey)) {
				try {
					sum += hashMap.get(randomKey) + data[randomKey]
							+ keys[randomKey];
				} catch (NoSuchKeyExistsException e) {
					sum++;
				}
			}
		}

		System.out.println("*** " + sum + " ***");
	}

	public static void main(String[] args) throws InterruptedException {
		System.out.println("Running test...");

		runTest(true);
		for (int i = 0; i < 1; i++) {
			System.out.println("DATASET SIZE: " + DATASET_SIZE);
			runJavaSetTest(false);
			runTest(false);
			System.gc();
			DATASET_SIZE *= 2;
		}
	}
}
